package com.ccteam.fluidmusic.repositories.search

import android.content.Context
import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer
import androidx.datastore.dataStore
import com.ccteam.fluidmusic.datastore.protobuf.CurrentSearchProtos
import com.ccteam.fluidmusic.datastore.protobuf.UserInfoProtos
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
import java.io.InputStream
import java.io.OutputStream
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author Xiaoc
 * @since 2021/3/25
 */
private const val currentSearchDataStoreFileName = "currentSearch.pb"

/**
 * 当前用户信息暂存的DataStore
 */
val Context.currentSearchDataStore by dataStore(
    fileName = currentSearchDataStoreFileName,
    serializer = CurrentSearchSerializer
)

/**
 * [UserInfoProtos.UserInfo] 的序列化器
 * 为什么要写这个是因为Java自带序列化用了耗费资源性能的反射
 * 而Android利用该序列化器将其显式调用防止耗费多余性能
 */
@Suppress("BlockingMethodInNonBlockingContext")
private object CurrentSearchSerializer: Serializer<CurrentSearchProtos.CurrentSearch> {
    override val defaultValue: CurrentSearchProtos.CurrentSearch
        get() = CurrentSearchProtos.CurrentSearch.getDefaultInstance()

    override suspend fun readFrom(input: InputStream): CurrentSearchProtos.CurrentSearch {
        return withContext(Dispatchers.IO){
            try {
                // 是编译器自动生成的，用于读取并解析 input 的消息
                return@withContext CurrentSearchProtos.CurrentSearch.parseFrom(input)
            } catch (e: Exception){
                throw CorruptionException("无法读取Proto内容 ${e.message}")
            }
        }

    }

    override suspend fun writeTo(t:CurrentSearchProtos.CurrentSearch, output: OutputStream) {
        // t.writeTo(output) 是编译器自动生成的，用于写入序列化消息
        withContext(Dispatchers.IO){
            t.writeTo(output)
        }
    }

}

@Singleton
class CurrentSearchRepository @Inject constructor(
    @ApplicationContext private val context: Context
){

    /**
     * 编辑搜索记录内容
     * 最多存储20条记录，如果多余20条会将最古老的一条去除
     * 存储为倒序存储，需要自行设置颠倒顺序
     */
    suspend fun editCurrentContent(searchKey: String){
        context.currentSearchDataStore.updateData {
            // 如果搜索记录超过20条，则删除最后一条再进行设置，保证搜索记录保持在20条不增加更多
            if(it.searchKeyCount >= 20){
                val items = it.searchKeyList.toMutableList()
                items.removeAt(0)
                items.add(searchKey)
                return@updateData it.toBuilder().clearSearchKey().addAllSearchKey(items).build()
            }
            it.toBuilder().addSearchKey(searchKey).build()
        }
    }

    /**
     * 编辑搜索记录内容
     * 最多存储20条记录，如果多余20条会将最古老的一条去除
     * 存储为倒序存储，需要自行设置颠倒顺序
     */
    fun getCurrentContent(): Flow<CurrentSearchProtos.CurrentSearch>{
        return context.currentSearchDataStore.data
    }
}